/*
 * Copyright (C) 2008 Derek James and Philip Tucker
 * 
 * This file is part of ANJI (Another NEAT Java Implementation).
 * 
 * ANJI is free software; you can redistribute it and/or modify it under the
 * terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option) any later
 * version.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 * Place, Suite 330, Boston, MA 02111-1307 USA
 * 
 * created by ptucker
 */
package com.anji.moorph;

import java.awt.Image;
import java.util.ArrayList;
import java.util.List;

import org.jgap.BulkFitnessFunction;
import org.jgap.Chromosome;

import com.anji.integration.TranscriberException;
import com.anji.util.Configurable;
import com.anji.util.Properties;

/**
 * This class evaluates chromosomes by transcribing them with MOORPH into 2d
 * images, evaluating them by showing them to a human viewer, and assigning
 * fitness values.
 * 
 * TODO(ptucker) 3d
 * 
 * @author ptucker
 */
public class MoorphFitnessFunction implements BulkFitnessFunction, Configurable {

  private static final int MAX_FITNESS = 100000;

  private static final int WINNER_SCORE = 100;

  private static final int LOSER_SCORE = 0;

  private ImageTransciber transcriber = new ImageTransciber();

  private MoorphChooser chooser = null;

  public void init(Properties props) throws Exception {
    transcriber.init(props);
  }

  private void evaluate(final List<Chromosome> subjects,
      final List<Image> images) {
    if (subjects.size() != images.size()) {
      throw new IllegalArgumentException("wrong number of subjects "
          + subjects.size() + " for images " + images.size());
    }

    if (chooser != null) {
      chooser.dispose();
    }

    MoorphChooser.ChoiceListener choiceListener =
        new MoorphChooser.ChoiceListener() {
          public void choose(int index) {
            for (int i = 0; i < subjects.size(); ++i) {
              subjects.get(i).setFitnessValue(
                  i == index ? WINNER_SCORE : LOSER_SCORE);
            }
          }
        };
    chooser = new MoorphChooser(choiceListener, images);
    chooser.setVisible(true);
    chooser.waitForUser();
  }

  /**
   * Transcribe each chromosome into an image and evaluate them.
   */
  public void evaluate(List<Chromosome> subjects) {
    // Transcribe.
    List<Image> images = new ArrayList<Image>();
    for (Chromosome subject : subjects) {
      try {
        images.add(transcriber.transcribeImage(subject));
      } catch (TranscriberException ex) {
        throw new IllegalStateException("failure transcribing " + subject, ex);
      }
    }

    // Evaluate.
    evaluate(subjects, images);
  }

  public int getMaxFitnessValue() {
    return MAX_FITNESS;
  }
}
